package com.campus.common.utils;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ExportParams;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.poifs.crypt.EncryptionInfo;
import org.apache.poi.poifs.crypt.EncryptionMode;
import org.apache.poi.poifs.crypt.Encryptor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

@Slf4j
public class EasyPoiUtils {
    /**
     * @param file       文件
     * @param headerRows 忽略头行数
     * @param pojoClass  转换的实体
     * @return List<User>  返回的集合
     * @Title: importData
     * @Description: 导入excle 数据
     */
    public static <T> List<T> importData(MultipartFile file, Integer titleRows, Integer headerRows,
                                         Class<T> pojoClass) {
        //判断文件是否存在
        if (file == null) {
            log.error("文件不存在！");
            throw new IllegalArgumentException("文件不存在！");
        }
        //获得文件名
        String fileName = file.getOriginalFilename();
        //判断文件是否是excel文件
        if (!fileName.endsWith("xls") && !fileName.endsWith("xlsx")) {
            log.error(fileName + "不是excel文件");
            throw new IllegalArgumentException(fileName + "不是excel文件！");
        }

        ImportParams params = new ImportParams();
        params.setNeedVerify(true); //是否开启校验
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows); //头行忽略的行数
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * @param list      导出的数据
     * @param title     文件标题
     * @param sheetName sheet名称
     * @param pojoClass 集合的类
     * @param fileName  文件名
     * @param response
     * @return void
     * @Title: exportExcel
     * @Description: 导出excel
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass, String fileName, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(title, sheetName), pojoClass, list);
        if (workbook != null) {
            try {
                String excelPassword = null;

                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

                if(requestAttributes != null){
                    excelPassword = requestAttributes.getRequest().getParameter("excelPassword");
                }

                if(StringUtils.isNotBlank(excelPassword)){
                    exportEncryptExcel(workbook, fileName, response, excelPassword);
                }else{
                    response.setCharacterEncoding("UTF-8");
                    response.setHeader("content-Type", "application/vnd.ms-excel");
                    response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1) + ".xlsx");
                    workbook.write(response.getOutputStream());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 导出Excel
     *
     * @param workbook workbook流
     * @param fileName 文件名
     * @param response 响应
     */
    public static void exportExcel(Workbook workbook, String fileName, HttpServletResponse response) {
        // 输出文件
        try (OutputStream out = response.getOutputStream()) {
            // 获取文件名并转码
            String name = URLEncoder.encode(fileName, "UTF-8");
            // 编码
            response.setCharacterEncoding("UTF-8");
            // 设置强制下载不打开
            response.setContentType("application/force-download");
            // 下载文件的默认名称
            response.setHeader("Content-Disposition", "attachment;filename=" + name + ".xlsx");
            // 输出表格
            workbook.write(out);
        } catch (IOException e) {
            log.error("文件导出异常,详情如下:{}", e.getMessage());
        } finally {
            try {
                if (workbook != null) {
                    // 关闭输出流
                    workbook.close();
                }
            } catch (IOException e) {
                log.error("文件导出关闭输出流失败,详情如下:{}", e.getMessage());
            }
        }
    }

    /**
     * 导出一个需要密码打开的Excel
     *
     * @param workbook workbook流
     * @param fileName 文件名
     * @param response 响应
     */
    public static void exportEncryptExcel(Workbook workbook, String fileName, HttpServletResponse response, String password) throws Exception {
        //
        if (StringUtils.isNotBlank(password)) {
            // 文件名
            fileName = fileName + ".xlsx";

            // 创建一个字节数组输出流
            ByteArrayOutputStream workbookOutput = new ByteArrayOutputStream();
            workbook.write(workbookOutput);
            workbookOutput.flush();

            // 创建一个字节数组输入流
            ByteArrayInputStream workbookInput = new ByteArrayInputStream(workbookOutput.toByteArray());

            // 加密
            EncryptionInfo info = new EncryptionInfo(EncryptionMode.agile);
            Encryptor enc = info.getEncryptor();
            enc.confirmPassword(password);

            // 创建一个POIFS 文件系统
            POIFSFileSystem poifsFileSystem = new POIFSFileSystem();
            OPCPackage opc = OPCPackage.open(workbookInput);
            OutputStream outputStream = enc.getDataStream(poifsFileSystem);
            opc.save(outputStream);
            outputStream.close();
            opc.close();
            workbookOutput = new ByteArrayOutputStream();
            poifsFileSystem.writeFilesystem(workbookOutput);
            workbookOutput.flush();

            // 获取文件名并转码
            String name = URLEncoder.encode(fileName, "UTF-8");
            // 编码
            response.setCharacterEncoding("UTF-8");
            // 设置强制下载不打开
            response.setContentType("application/force-download");
            // 下载文件的默认名称
            response.setHeader("Content-Disposition", "attachment;filename=" + name);
            byte[] buff = new byte[1024];
            BufferedInputStream bufferedInputStream = null;

            try {
                OutputStream responseOutputStream = response.getOutputStream();
                bufferedInputStream = new BufferedInputStream(new ByteArrayInputStream(workbookOutput.toByteArray()));

                for (int i = bufferedInputStream.read(buff); i != -1; i = bufferedInputStream.read(buff)) {
                    responseOutputStream.write(buff, 0, buff.length);
                    responseOutputStream.flush();
                }
            } catch (IOException e) {
                log.error("文件导出失败,详情如下:{}", e.getMessage());
            } finally {
                if (bufferedInputStream != null) {
                    try {
                        bufferedInputStream.close();
                    } catch (IOException e) {
                        log.error("文件导出关闭输出流失败,详情如下:{}", e.getMessage());
                    }
                }

            }
        } else {
            exportExcel(workbook, fileName, response);
        }

    }

    /**
     * description:  动态导出excel 表头
     * create by heyanfeng at 2019-09-30 10:10
     *
     * @param fileName     文件名称
     * @param exportParams 导出excel title 和sheet 的定义
     * @param entities     表头行的定义
     * @param list         导出的数据
     * @return
     * @response
     */
    public static void exportExcel(String fileName, ExportParams exportParams, List<ExcelExportEntity> entities, List<Map<String, Object>> list, HttpServletResponse response) {
        defaultExport(fileName, exportParams, entities, list, response);
    }

    private static void defaultExport(String fileName, ExportParams exportParams, List<ExcelExportEntity> entities, List<Map<String, Object>> list, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entities, list);
        downLoadExcel(fileName, response, workbook);
        //downExcel(response,workbook,fileName);
    }



    public static Workbook createExcel(String fileName, ExportParams exportParams, List<ExcelExportEntity> entities, List<Map<String, Object>> list) {
        return ExcelExportUtil.exportExcel(exportParams, entities, list);
    }

    public static void downExcel(HttpServletResponse response, Workbook workbook, String fileName)  {
        response.reset();
        response.setContentType("application/x-msdownload; charset=UTF-8");
        response.setCharacterEncoding("utf-8");
        try {
            response.setHeader("Content-disposition", "attachment;filename=" + new String(fileName.getBytes(StandardCharsets.UTF_8), "iso8859-1") + ".xlsx");
            response.flushBuffer();
            workbook.write(response.getOutputStream());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * description: 下载excel
     * create by heyanfeng at 2019-09-30 10:09
     *
     * @param fileName
     * @param response
     * @param workbook
     */
    public static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
        try {
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Type", "application/json");
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            log.error("excel异常:{}", e.getMessage());
        }
    }

    public static XSSFFont getFont(XSSFWorkbook workbook, String fontName, short fontSize, short color, Boolean bold) {
        XSSFFont font = workbook.createFont();
        if(StringUtils.isNotBlank(fontName)) {
            font.setFontName(fontName);
        }
        font.setFontHeightInPoints(fontSize);
        font.setColor(color);
        font.setBold(bold);
        return font;
    }

    public static XSSFCellStyle getCellStyle(XSSFWorkbook workbook, XSSFFont font, Boolean wrapText, HorizontalAlignment alignment, VerticalAlignment va, Short bgColor, FillPatternType fillPattern, Boolean lock) {
        XSSFCellStyle cellStyle = workbook.createCellStyle();
        if (font != null) {
            cellStyle.setFont(font);
        }
        cellStyle.setBorderBottom(BorderStyle.THIN);
        cellStyle.setBorderLeft(BorderStyle.THIN);
        cellStyle.setBorderRight(BorderStyle.THIN);
        cellStyle.setBorderTop(BorderStyle.THIN);
        cellStyle.setWrapText(wrapText);
        cellStyle.setAlignment(alignment);
        cellStyle.setVerticalAlignment(va);
        if(bgColor!=null) {
            cellStyle.setFillForegroundColor(bgColor);
        }
        if(fillPattern!=null){
            cellStyle.setFillPattern(fillPattern);
        }
        cellStyle.setLocked(lock);
        return cellStyle;
    }

}